﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using System.Data;
using Dapper;
using Dapper.Contrib.Extensions;

namespace Topro.Application.Impl
{
    using Topro.Application.Interface;
    using Topro.Db;
    using Topro.Entity;
    using Topro.Entity.Enum;
    using Topro.Entity.Query;
    using Topro.Entity.Request.InventoryItem;
    using Topro.Entity.Request.StockIn;
    using Topro.Entity.Response.Inventory;
    using Topro.Entity.Response.StockIn;
    using Topro.Entity.Tables;
    using Topro.Log;
    using Topro.Util;

    /// <summary>
    /// 入库业务接口实现
    /// </summary>
    public class StockInServiceImpl: StockInService
    {
        #region 注入

        /// <summary>
        /// 
        /// </summary>
        private readonly IUId _uid;

        /// <summary>
        /// db
        /// </summary>
        private readonly IDb _db;

        /// <summary>
        /// loggerService
        /// </summary>
        private readonly LoggerService _loggerService;

        /// <summary>
        /// 
        /// </summary>
        private readonly ASRSJOBService _asrsJOBService;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dapperFactory"></param>
        /// <param name="logger"></param>
        public StockInServiceImpl(IDb db, LoggerService loggerService, ASRSJOBService asrsJOBService, IUId uid)
        {
            _uid = uid;
            _db = db;
            _loggerService = loggerService;
            _asrsJOBService = asrsJOBService;
        }
        #endregion

        /// <summary>
        /// 入库
        /// </summary>
        /// <param name="stockIn"></param>
        /// <param name="inventoryItem">明细</param>
        public JResult Save(StockInSaveRequest stockIn, List<InventoryItemSaveRequest> inventoryItem)
        {
            var result = new JResult()
            {
                Success = false
            };

            //创建连接池
            var dbConnection = _db.DbConnection;
            //开始事务
            var transaction = _db.Begin(dbConnection);

            try
            {
                //验证是否为空
                if (string.IsNullOrEmpty(stockIn.OrderId))
                    throw new Exception("订单号不能为空.");
                //实托
                if(stockIn.IsContainer == (int)IsContainer.实)
                {
                    if (!inventoryItem.Any())
                        throw new Exception("实托明细不能为空.");
                }
                //托盘
                if(!stockIn.ContainerCode.HasValue)
                    throw new Exception("托盘不能为空.");
                //库存托盘验证
                var inventoryQuerySql = "SELECT * FROM t_inventory WHERE OrderType=@OrderType AND InventoryQty>0 AND Status=@Status AND ContainerCode=@ContainerCode";
                var inventorys = dbConnection.Query<InventoryResponse>(inventoryQuerySql, new { OrderType = (int)InventoryType.入库, Status = (int)InventoryStatus.完成, ContainerCode = stockIn.ContainerCode.Value }, transaction);
                if (inventorys.Any())
                    throw new Exception("托盘已存在.");

                #region 库位分配
                //所有库位记录
                var warehouseUnits = dbConnection.Query<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,ContainerCode,IsContainer from t_warehouseunit where type=@type and status=1 and id NOT IN(SELECT i.WarehouseUnitId FROM t_inventory i WHERE i.Status=2 and i.InventoryQty>0) order by Pai,Lie,Ceng ASC", new { type = stockIn.Type.Value }, transaction);

                if (warehouseUnits == null && warehouseUnits.Any())
                    throw new Exception("暂无空闲仓位.");

                if (stockIn.WarehouseUnitId <= 0)
                {
                    #region 查询一排
                    if (stockIn.WarehouseUnitId == 0)
                    {
                        var emptyOneWarehouseUnits = warehouseUnits.Where(c => c.Pai == (int)WarehouseUnitPai.一排 && c.Locked == (int)WarehouseLocked.否);
                        if (emptyOneWarehouseUnits.Any())
                        {
                            var emptyOneWarehouseUnit = emptyOneWarehouseUnits.FirstOrDefault();
                            if(emptyOneWarehouseUnit!=null)
                                stockIn.WarehouseUnitId = emptyOneWarehouseUnit.Id;
                        }
                    }
                    #endregion

                    #region 查询二排
                    if (stockIn.WarehouseUnitId == 0)
                    {
                        var emptyTwoWarehouseUnits = warehouseUnits.Where(c => c.Pai == (int)WarehouseUnitPai.二排 && c.Locked == (int)WarehouseLocked.否);
                        if (emptyTwoWarehouseUnits.Any())
                        {
                            var emptyTwoWarehouseUnit = emptyTwoWarehouseUnits.FirstOrDefault();
                            if (emptyTwoWarehouseUnit != null)
                                stockIn.WarehouseUnitId = emptyTwoWarehouseUnit.Id;
                        }
                    }
                    #endregion
                }
                else
                {
                    #region 验证是否占用
                    var emptyWarehouseUnit = warehouseUnits.FirstOrDefault(c => c.Id == stockIn.WarehouseUnitId && c.Locked == (int)WarehouseLocked.否);
                    if(emptyWarehouseUnit==null)
                        throw new Exception("分配的仓位不存在或被占用.");
                    #endregion
                }

                if (stockIn.WarehouseUnitId <= 0)
                    throw new Exception("仓位分配失败请重试.");

                var warehouseUnit = warehouseUnits.FirstOrDefault(c => c.Id == stockIn.WarehouseUnitId);
                if(warehouseUnit==null)
                    throw new Exception("仓位分配失败请重试.");

                var warehouseCode = warehouseUnit.Code;
                #endregion

                #region 之前
                {
                    //所有库位记录
                    var existWarehouseUnit = dbConnection.QueryFirstOrDefault<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,Status,ContainerCode,IsContainer from t_warehouseunit where Id=@Id", new { Id = stockIn.WarehouseUnitId }, transaction);
                    if (existWarehouseUnit != null && existWarehouseUnit.Locked == (int)WarehouseLocked.是)
                        throw new Exception("库位已锁定、请换一个试试");

                    _loggerService.Add(new OperLog()
                    {
                        Level = 10,
                        Source = 10,
                        Message = $"创建入库单{stockIn.OrderId},仓位{warehouseCode}-之前是否锁定({existWarehouseUnit.Locked})",
                        Exception = "",
                        Ip = "127.0.0.1",
                        CreatedBy = stockIn.CreatedBy
                    });
                }
                #endregion

                #region 锁定库位
                //锁定库位Sql语句
                var updateWarehouseUnitSql = "UPDATE t_warehouseunit SET Locked=@Locked WHERE Id=@Id";
                //执行锁定
                int updateStatus = dbConnection.Execute(updateWarehouseUnitSql, new { Locked = (int)WarehouseLocked.是,Id = stockIn.WarehouseUnitId }, transaction);
                if (updateStatus <= 0)
                    throw new Exception("库位锁定失败");
                #endregion

                #region 新增
                if (stockIn.IsContainer == (int)IsContainer.空)
                {
                    var inventoryId = dbConnection.Insert<Inventory>(new Inventory()
                    {
                        OrderType = (int)InventoryType.入库,
                        ResourceId = stockIn.OrderId,
                        SourceId = "",
                        PartNo = "",
                        ProductName = "",
                        Qty = 1,
                        InventoryQty = 1,
                        LotNo = "",
                        Grade = "",
                        WarehouseUnitId = stockIn.WarehouseUnitId,
                        ContainerCode = stockIn.ContainerCode.Value,
                        IsContainer = stockIn.IsContainer,
                        Remark = stockIn.Remark,
                        Status = (int)InventoryStatus.待处理,
                        CreatedBy = stockIn.CreatedBy,
                        CreateTime = DateTime.Now
                    }, transaction);
                    if (inventoryId <= 0)
                    {
                        throw new Exception("操作库存失败.");
                    }
                }
                else if (stockIn.IsContainer == (int)IsContainer.实)
                {
                    inventoryItem.ForEach(item =>
                    {
                        //数量验证
                        if (item.Qty <= 0)
                            throw new Exception("数量必填项.");
                        var inventoryId = dbConnection.Insert<Inventory>(new Inventory()
                        {
                            OrderType = (int)InventoryType.入库,
                            ResourceId = stockIn.OrderId,
                            SourceId = "",
                            PartNo = item.PartNo,
                            ProductName = item.ProductName,
                            Qty = item.Qty,
                            InventoryQty = item.Qty,
                            LotNo = item.LotNo,
                            Grade = item.Grade,
                            WarehouseUnitId = stockIn.WarehouseUnitId,
                            ContainerCode = stockIn.ContainerCode.Value,
                            IsContainer = stockIn.IsContainer,
                            Remark = stockIn.Remark,
                            Status = (int)InventoryStatus.待处理,
                            CreatedBy = stockIn.CreatedBy,
                            CreateTime = DateTime.Now
                        }, transaction);
                        if (inventoryId <= 0)
                        {
                            throw new Exception("操作库存失败.");
                        }
                    });
                }
                else
                {
                    throw new Exception("是否空托参数错误.");
                }
                #endregion

                #region 日志
                {
                    _loggerService.Add(new OperLog()
                    {
                        Level = 10,
                        Source = 10,
                        Message = $"创建入库单{stockIn.OrderId},仓位{warehouseUnit.Pai}-{warehouseUnit.Lie}-{warehouseUnit.Ceng}",
                        Exception = "",
                        Ip = "127.0.0.1",
                        CreatedBy = stockIn.CreatedBy
                    });
                }
                #endregion

                #region 指令
                var asrsjob = new ASRSJOB()
                {
                    BINDID = stockIn.OrderId,
                    TYPE = "In",
                    CTNCODE = stockIn.ContainerCode.Value.ToString(),
                    ORIPORT = "",
                    TARPORT = warehouseUnit.Code,
                    STATE = (int)CommandStatus.待操作,
                    CREATEDATE = DateTime.Now,
                };

                if(stockIn.StationNo.Equals(1))
                {
                    asrsjob.ORIPORT = "1-10-01-01";
                }
                else if (stockIn.StationNo.Equals(2))
                {
                    asrsjob.ORIPORT = "1-10-01-02";
                }
                else if (stockIn.StationNo.Equals(4))
                {
                    asrsjob.ORIPORT = "1-10-01-04";
                }
                else if (stockIn.StationNo.Equals(6))
                {
                    asrsjob.ORIPORT = "1-10-01-06";
                }
                else if (stockIn.StationNo.Equals(8))
                {
                    asrsjob.ORIPORT = "1-10-01-08";
                }
                else if (stockIn.StationNo.Equals(10))
                {
                    asrsjob.ORIPORT = "1-10-01-10";
                }
                else
                {
                    throw new Exception("站台参数验证失败.");
                }
                //新增
                var commandId = dbConnection.Insert<ASRSJOB>(asrsjob, transaction);
                if (commandId <= 0)
                {
                    throw new Exception("操作失败.");
                }


                #endregion

                #region 之后
                {
                    //所有库位记录
                    var existWarehouseUnit = dbConnection.QueryFirstOrDefault<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,Status,ContainerCode,IsContainer from t_warehouseunit where Id=@Id", new { Id = stockIn.WarehouseUnitId }, transaction);
                    if (existWarehouseUnit != null)
                    {
                        _loggerService.Add(new OperLog()
                        {
                            Level = 10,
                            Source = 10,
                            Message = $"创建入库单{stockIn.OrderId},仓位{warehouseCode}-之后是否锁定({existWarehouseUnit.Locked})",
                            Exception = "",
                            Ip = "127.0.0.1",
                            CreatedBy = stockIn.CreatedBy
                        });
                    }
                }
                #endregion

                result.Success = true;
                result.Message = "操作成功.";
                //提交事务
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();

                result.Success = false;
                result.Message = ex.Message;
            }
            finally
            {
                transaction.Dispose();
                dbConnection.Close();
                dbConnection.Dispose();
            }

            return result;
        }


        #region 空闲库位查询
        /// <summary>
        /// 空闲库位查询
        /// </summary>
        /// <param name="warehouseUnits">所有空闲库位</param>
        public WarehouseUnit EmptyWarehouseUnitQuery(List<WarehouseUnit> warehouseUnits)
        {
            if(warehouseUnits==null || !warehouseUnits.Any())
                return null;

            return warehouseUnits.FirstOrDefault(c => c.Pai == (int)WarehouseUnitPai.一排 || c.Pai == (int)WarehouseUnitPai.四排);
        }
        #endregion

        #region 移库操作
        /// <summary>
        /// 移库操作
        /// </summary>
        /// <param name="transaction"></param>
        /// <param name="warehouseUnits"></param>
        /// <param name="fromWarehouseUnit"></param>
        /// <exception cref="Exception"></exception>
        public void MoveWarehouseUnit(IDbConnection dbConnection,IDbTransaction transaction,List<WarehouseUnit> warehouseUnits, WarehouseUnit fromWarehouseUnit)
        {
            //获取一个空库位
            var emptyWarehouseUnit = this.EmptyWarehouseUnitQuery(warehouseUnits);
            if (emptyWarehouseUnit != null)
            {
                var moveasrsjob = new ASRSJOB()
                {
                    BINDID = String.Empty,
                    TYPE = "Move",
                    CTNCODE = "",
                    ORIPORT = fromWarehouseUnit.Code,
                    TARPORT = emptyWarehouseUnit.Code,
                    STATE = (int)CommandStatus.待操作,
                    CREATEDATE = DateTime.Now,
                };

                //新增
                var moveasrsjobId = dbConnection.Insert<ASRSJOB>(moveasrsjob, transaction);
                if (moveasrsjobId <= 0)
                {
                    throw new Exception("移库操作失败.");
                }
            }
            else
            {
                throw new Exception("你分配的仓位前排已占用,请换一个试试.");
            }
        }
        #endregion

        #region 获取未锁定记录
        /// <summary>
        /// 获取未锁定记录
        /// </summary>
        /// <returns></returns>
        public List<WarehouseUnit> GetNotLockeds(IDbTransaction transaction)
        {
            return _db.DbConnection.Query<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,ContainerCode,IsContainer from t_warehouseunit where Locked=@Locked order by Pai,Lie,Ceng ASC", new { Locked = (int)WarehouseLocked.否 }, transaction).ToList();
        }
        #endregion

        #region 获取所有库位记录
        /// <summary>
        /// 获取未锁定记录
        /// </summary>
        /// <returns></returns>
        public List<WarehouseUnit> GetWarehouseUnits(IDbTransaction transaction)
        {
            return _db.DbConnection.Query<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,ContainerCode,IsContainer from t_warehouseunit order by Pai,Lie,Ceng ASC", new { Locked = (int)WarehouseLocked.否 }, transaction).ToList();
        }
        #endregion

        #region 获取锁定记录
        /// <summary>
        /// 获取未锁定记录
        /// </summary>
        /// <returns></returns>
        public List<WarehouseUnit> GetLockeds(IDbTransaction transaction)
        {
            return _db.DbConnection.Query<WarehouseUnit>("select Id,Type,Code,Pai,Lie,Ceng,Locked,ContainerCode,IsContainer from t_warehouseunit where Locked=@Locked order by Pai,Lie,Ceng ASC", new { Locked = (int)WarehouseLocked.是 }, transaction).ToList();
        }
        #endregion

        #region 入库查询
        /// <summary>
        /// 入库查询
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public DataGrid<StockInQueryResponse> Pager(StockInQuery query)
        {
            var pageIndex = query.PageIndex <= 0 ? 0 : (query.PageIndex - 1) * query.PageSize;

            var files = "si.Id,si.OrderId,si.WarehouseUnitId,CONCAT(wu.Pai,'-',wu.Lie,'-',wu.Ceng,'-',wu.Fix) as WarehouseUnitTostring,si.ProductName,si.ContainerType,si.IsContainer,si.Coordinate,si.Quantity,si.StationNo,si.Status,si.Remark,si.CreatedBy,(SELECT Account FROM user WHERE Id=si.CreatedBy) as CreatedByTostring,si.CreateTime";
            var tableName = "t_stockin si INNER JOIN t_warehouseunit wu ON si.WarehouseUnitId=wu.Id";
            var orderby = "ORDER BY si.CreateTime DESC";
            var where = "where 0=0";

            #region 条件
            if (query.Status.Any())
            {
                where += string.Format(" And si.Status in({0})", string.Join(",", query.Status));
            }
            if (!string.IsNullOrEmpty(query.OrderId))
            {
                where += string.Format(" And si.OrderId like '%{0}%'", query.OrderId);
            }
            #endregion

            var sb = new StringBuilder();

            sb.AppendFormat("SELECT COUNT(1) FROM {0} {1};", tableName, where);
            //sb.AppendFormat("select {0} from {1} {2} {3} offset {4} rows fetch next {5} rows only", files, tableName, where, orderby, pageIndex, query.PageSize);
            sb.AppendFormat("SELECT {0} FROM {1} {2} {3} LIMIT {4},{5};", files, tableName, where, orderby, pageIndex, query.PageSize);
            using (var multi = _db.DbConnection.QueryMultiple(sb.ToString()))
            {
                var count = multi.ReadFirst<int>();

                var list = multi.Read<StockInQueryResponse>();

                return new DataGrid<StockInQueryResponse>()
                {
                    Rows = list,
                    Total = count
                };
            }
        }
        #endregion
    }
}
